#ifndef GENERAL_TCPSERVER_H
#define GENERAL_TCPSERVER_H

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#include <WinSock2.h>
#endif

#ifdef linux
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define EVENT__HAVE_PTHREADS
#endif

#include <stdint.h>
#include <iostream>
#include <mutex>
#include <thread>
#include <map>
#include <functional>

using  namespace std;

class TcpServerLibevent;
// tcp 连接
class ConnectionLibevent{
public:
  ConnectionLibevent(TcpServerLibevent *p,
	struct bufferevent*v,
	uint32_t fd,
	struct sockaddr_in *p1);

	ConnectionLibevent(struct bufferevent*v,
	uint32_t fd,
	struct sockaddr_in *p1);
  
	virtual int OnRecv(char *p,uint32_t len);  // data ready callback
	virtual int OnClose();                     // close callback 
	virtual int OnWrite();                     // write data done callback
	int WriteData(const char *p,uint16_t len);
	int SetServer(TcpServerLibevent *);
	TcpServerLibevent *Server();
	string IpAddress();
	uint32_t SocketFd();
	int Close();
private:
	int m_bytes_send;
	int m_bytes_recv;
	TcpServerLibevent *m_parent_server;
	struct bufferevent *m_event;
	struct sockaddr_in *m_addr;
	uint32_t m_fd;
};

// 管理服务端
class TcpServerLibevent{
	typedef enum{
		RUNNING,
		STOP,
		FAIL
	}SERVER_STATUS;
public:
	typedef std::function<ConnectionLibevent*(struct bufferevent *ev,uint32_t fd,struct sockaddr_in *p1)> OnAccept;
	TcpServerLibevent(int port,string bindip);
	SERVER_STATUS Status();
	~TcpServerLibevent();
	int StartServerAndRunSync(); //  同步启动服务器
	int StartServerAsync(); // 异步启动服务
	int RemoveConnection(uint32_t );
	int SetNewConnectionHandle(OnAccept);
	int AddConnection(uint32_t fd,ConnectionLibevent *p);
	friend struct ServerCallbacks;
private:
	uint32_t  m_port;  // 监听端口号
	string  m_bind_ip;  // 绑定端口号
	int m_current_conection; //  当前连接数目
	uint16_t m_backlog;
	struct sockaddr_in m_server_addr;  // 服务器地址
	struct event_base *m_event_base;
	struct evconnlistener*m_event_listener;  
	SERVER_STATUS m_status;
	thread *m_thread;
	map<uint32_t,ConnectionLibevent*> m_map_client;
	OnAccept m_handle_accept;
};

#endif